package net.jueb.protobufs.codec;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.CorruptedFrameException;

import java.util.HashMap;
import java.util.List;

import com.google.protobuf.CodedInputStream;

/**
 * 读取标记头来实现后续解码器的加入
 * @author Administrator
 *
 */
public class ProtobufsDispatcherDecoder extends ByteToMessageDecoder {
	private  HashMap<Byte,ProtobufsDecoder> decoders;
	public ProtobufsDispatcherDecoder(HashMap<Byte,ProtobufsDecoder> decoders) 
	{
		this.decoders=decoders;
	}
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        in.markReaderIndex();
        final byte[] buf = new byte[5];
        for (int i = 0; i < buf.length; i ++) 
        {
            if (!in.isReadable()) 
            {
                in.resetReaderIndex();
                return;
            }

            buf[i] = in.readByte();
            if (buf[i] >= 0) 
            {
                int length = CodedInputStream.newInstance(buf, 0, i + 1).readRawVarint32();
                if (length < 0) 
                {
                    throw new CorruptedFrameException("negative length: " + length);
                }
                if (in.readableBytes() < length) 
                {
                    in.resetReaderIndex();
                    return;
                } else {                	
                	ByteBuf in2=in.readBytes(length);//获得包含头+protobuf数据的字节数组
            		byte type=in2.readByte();//读取类型头
            		if(decoders.containsKey(type) && decoders.get(type)!=null)
            		{
            			if(ctx.pipeline().names().contains("ProtobufsDecoder"))
            			{
            				ctx.pipeline().remove("ProtobufsDecoder");
            			}
            			ctx.fireChannelRead("fireChannelRead1");
            			ctx.pipeline().addAfter("ProtobufsDispatcherDecoder", "ProtobufsDecoder", decoders.get(type));
            			out.add(in2);//将类型头后的数据发送给下一个handler
            			ctx.fireChannelRead("fireChannelRead2");
            			ctx.fireExceptionCaught(new Throwable("测试异常"));
            			ctx.fireUserEventTriggered("测试事件");
            			ctx.fireChannelRead("fireChannelRead3");
            		}
                    return;
                }
            }
        }
        // Couldn't find the byte whose MSB is off.
        throw new CorruptedFrameException("length wider than 32-bit");
    }
}
